#include "pch.h"


RenderObjectManager::RenderObjectManager()
{

}

RenderObjectManager::~RenderObjectManager()
{
	m_RenderSpriteMap.clear();
}

void RenderObjectManager::Initialize()
{
	
}

std::shared_ptr<Sprite> RenderObjectManager::CreateSprite(const std::wstring& texture, const float2& position, const float2& size, float angle_deg)
{
	uint uid = GenerateKey();
	std::shared_ptr<Sprite> s(new Sprite());
	s->uid = uid;
	s->type = RenderObject::RenderSprite;
	s->SetTransform(position, angle_deg);
	s->SetScale(size);
	

	Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> view = CreateTexture(texture);
	s->SetTexture(view);

	m_RenderSpriteMap.insert(std::make_pair(uid, s));
	return s;

}

void RenderObjectManager::AddSpriteToRenderList(Sprite* s, RenderObjectLayer layer)
{
	m_RenderLayer[layer].push_back(s);
}

Microsoft::WRL::ComPtr<ID3D11ShaderResourceView> RenderObjectManager::CreateTexture(const std::wstring& filename)
{
	auto itor = m_TextureDataMap.find(filename);
	if(itor != m_TextureDataMap.end())
	{
		TextureData& data = itor->second;
		data.textureShaderResourceView.Get()->AddRef();
		return data.textureShaderResourceView;
	}
	
	TextureData data; 
	BasicLoader^ loader = ref new BasicLoader(DirectX2DRender::Instance()->GetDevice().Get());
	
	loader->LoadTexture(ref new Platform::String(filename.c_str()), &data.texture, &data.textureShaderResourceView);

	m_TextureDataMap[filename] = data;
	return data.textureShaderResourceView;
}

void RenderObjectManager::Render(ID3D11DeviceContext1* context)
{
	RenderDeclaration^ rd = RenderDeclaration::Instance();
	context->IASetInputLayout(RenderDeclaration::Instance()->GetInputLayout().Get());
	context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	uint32 stride = sizeof(RectPointVertex);
	uint32 offset = 0;
	context->IASetVertexBuffers(0, 1, rd->GetSpriteVertexBuffer().GetAddressOf(), &stride, &offset);
	context->IASetIndexBuffer(rd->GetSpriteIndexBuffer().Get(), DXGI_FORMAT_R16_UINT, 0);


	context->VSSetConstantBuffers(0, 1, rd->GetConstantBufferGlobal().GetAddressOf());
	context->VSSetShader(rd->GetVertexShader().Get(), nullptr, 0);


	context->PSSetShader(rd->GetPixelShader().Get(), nullptr, 0);
	context->PSSetSamplers(0, 1, rd->GetSampler().GetAddressOf());

	for (uint i = 0; i < RenderObjectLayerNum; i++)
	{
		for (uint j = 0; j < m_RenderLayer[i].size(); j++)
		{
			RenderObject* r = m_RenderLayer[i][j];
			r->Render(context);
		}
		m_RenderLayer[i].clear();
	}

#ifdef _DEBUG

#endif
}

void RenderObjectManager::Update(float frame_time)
{
	const float clean_up_texture_interval = 10.f;
	static float clean_up_texture_timer = 0.f;

	const float clean_up_renderObject_interval = 9.f;
	static float clean_up_renderObject_timer = 0.f;

	clean_up_texture_timer += frame_time;
	clean_up_renderObject_timer += frame_time;


	
	if(clean_up_renderObject_timer > clean_up_renderObject_interval)
	{
		clean_up_renderObject_timer = 0.f;

		CleanUpRenderObject();
	}
	else if(clean_up_texture_timer > clean_up_texture_interval)
	{
		clean_up_texture_timer = 0.f;

		CleanUpTexture();
	}
	
		


	auto itor = m_RenderSpriteMap.begin();
	for(;itor != m_RenderSpriteMap.end(); itor ++)
	{
		itor->second->Update(frame_time);
	}

}

void RenderObjectManager::CleanUpTexture()
{
	auto itor = m_TextureDataMap.begin();
	while(itor != m_TextureDataMap.end())
	{
		TextureData& data = itor->second;
		if(data.textureShaderResourceView.Get())
		{
			data.textureShaderResourceView.Get()->AddRef();
			auto ref_count = data.textureShaderResourceView.Get()->Release();
			if(ref_count <= 1)
			{
				itor = m_TextureDataMap.erase(itor);
			}
			else
			{
				itor++;
			}
		}
		else
		{
			itor = m_TextureDataMap.erase(itor);
		}
		
	}
}

void RenderObjectManager::CleanUpRenderObject()
{
	auto itor = m_RenderSpriteMap.begin();
	while(itor != m_RenderSpriteMap.end())
	{
		
		if(itor->second.unique())
		{
			itor = m_RenderSpriteMap.erase(itor);
		}
		else
		{
			itor++;
		}
	}
	
}